#include "InputDevice.h"
#include "Logger\Logger.h"
#include "Base.h"

#if defined (_DEBUG)
#include "Memory\MemLeaks.h"
#endif

//-------------------------------------------------
CInputDevice::CInputDevice()
	: m_DIDevice(NULL)
	, m_DirectInput(NULL)
	, m_hWnd(NULL)
{

}

//-------------------------------------------------
CInputDevice::~CInputDevice()
{
	Uninitialize();
}

//-------------------------------------------------
bool CInputDevice::Initialize(LPDIRECTINPUT8 _directInput, HWND _hWnd, REFGUID _rguid, LPCDIDATAFORMAT _lpdf, bool _bExclusiveMode /* = false */)
{
	m_DirectInput	= _directInput;
	m_hWnd			= _hWnd;

	DWORD dwFlags = DISCL_FOREGROUND;

	if (_bExclusiveMode)
	{
		dwFlags |= DISCL_EXCLUSIVE;
	}
	else
	{
		dwFlags |= DISCL_NONEXCLUSIVE;
	}

	if(m_DIDevice)
	{
		m_DIDevice->Unacquire();
		CHECKED_RELEASE(m_DIDevice);
	}

	// Create Direct Input Device
	if ( FAILED(m_DirectInput->CreateDevice(_rguid, &m_DIDevice, NULL))) 
	{
		LOGGER->AddNewLog(ELL_ERROR, "CInputDevice::Initialize-> CreateDevice failed");
		return false; 
	}

	// set the correct device data format
	if ( FAILED(m_DIDevice->SetDataFormat(_lpdf))) 
	{
		LOGGER->AddNewLog(ELL_ERROR, "CInputDevice::Initialize-> SetDataFormat failed");
		return false; 
	}

	// set the cooperation level with windows
	if ( FAILED(m_DIDevice->SetCooperativeLevel(m_hWnd, dwFlags))) 
	{
		LOGGER->AddNewLog(ELL_ERROR, "CInputDevice::Initialize SetCoopLevel failed");
		return false; 
	}

	return true;
}

//-------------------------------------------------
void CInputDevice::Uninitialize()
{
	if(m_DIDevice)
	{
		m_DIDevice->Unacquire();
		CHECKED_RELEASE(m_DIDevice);
	}
}

//-------------------------------------------------
bool CInputDevice::GetData(Input::INPUT_DEVICE_TYPE _type, void *_pData, DWORD *_pDwNum)
{
	HRESULT hr=S_FALSE;
	size_t size=0;

	// is this a mouse?
	if (_type == Input::IDV_MOUSE) 
	{
		size = sizeof(DIDEVICEOBJECTDATA);

		hr = m_DIDevice->GetDeviceData((DWORD)size, (DIDEVICEOBJECTDATA*)_pData, _pDwNum, 0);
	}
	else 
	{
		if (_type == Input::IDV_KEYBOARD) 
			size = sizeof(char)*256;
		else 
			size = sizeof(DIJOYSTATE);

		hr = m_DIDevice->GetDeviceState((DWORD)size, _pData);
	}

	if (FAILED(hr)) 
	{
		// if lost or not yet acquired then acquire it at all costs
		if ( (hr == DIERR_NOTACQUIRED) || (hr == DIERR_INPUTLOST) ) 
		{
			hr = m_DIDevice->Acquire();
			while (hr == DIERR_INPUTLOST)
			{
				hr = m_DIDevice->Acquire();
			}

			// if another application is using this input device
			// we have to give up and try next frame
			if (hr==DIERR_OTHERAPPHASPRIO)
				return true;

			// if we got back device then try again to read data
			if (SUCCEEDED(hr)) 
			{
				if (_type == Input::IDV_MOUSE)
					hr = m_DIDevice->GetDeviceData((DWORD)size, (DIDEVICEOBJECTDATA*)_pData, _pDwNum, 0);
				else 
					hr = m_DIDevice->GetDeviceState((DWORD)size, _pData);
			}

			if (FAILED(hr)) 
				return false;
		}
		else 
			return false;
	}

	return true;
}